﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Globalization;
using System.Configuration;
using System.Security.Cryptography;
using System.Data;
using System.Linq.Expressions;
using Ivs.Core.Data;
using System.Web.Configuration;

namespace Ivs.Core.Common.Utilities
{
    public class Utilities
    {

        #region Validation

        public static bool isNullOrEmpty(object obj)
        {
            try
            {
                if (obj == null)
                    return true;
                if (obj.ToString().Trim().Equals(""))
                    return true;
                return false;
            }
            catch
            {
                return false;
            }
        }
        public static bool IsAlphaNumeric(string pText)
        {
            Regex regex = new Regex(@"^[A-Za-z0-9_]+$");
            return regex.IsMatch(pText);
        }

        public static bool IsNumber(string pText)
        {
            Regex regex = new Regex(@"^[-+]?[0-9]*\.?[0-9]+$");
            return regex.IsMatch(pText);
        }

        public static bool IsPositiveNumber(string pText)
        {
            Regex regex = new Regex(@"^[0-9]*\.?[0-9]+$");
            return regex.IsMatch(pText);
        }

        public static bool IsNumberic(string pValue)
        {
            foreach (Char c in pValue)
            {
                if (!Char.IsDigit(c))
                    return false;
            }
            return true;
        }
        public static bool IsNumeric(object Expression)
        {
            // Variable to collect the Return value of the TryParse method.
            bool isNum;

            // Define variable to collect out parameter of the TryParse method. If the conversion fails, the out parameter is zero.
            double retNum;

            // The TryParse method converts a string in a specified style and culture-specific format to its double-precision floating point number equivalent.
            // The TryParse method does not generate an exception if the conversion fails. If the conversion passes, True is returned. If it does not, False is returned.

            isNum = Double.TryParse(Convert.ToString(Expression), System.Globalization.NumberStyles.Any, System.Globalization.NumberFormatInfo.InvariantInfo, out retNum);
            return isNum;
        }
        public static bool IsInteger(string pValue)
        {
            try
            {
                int n = Convert.ToInt32(pValue);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public static bool isValidMaxLength(object obj, long maxLength)
        {
            try
            {
                if (isNullOrEmpty(obj))
                    return true;
                if (obj.ToString().Trim().Length <= maxLength)
                    return true;

                return false;
            }
            catch
            {
                return false;
            }
        }
        public static bool IsValidEmailAddress(string sEmail)
        {
            if (sEmail == null)
            {
                return false;
            }

            int nFirstAT = sEmail.IndexOf('@');
            int nLastAT = sEmail.LastIndexOf('@');

            if ((nFirstAT > 0) && (nLastAT == nFirstAT) &&
            (nFirstAT < (sEmail.Length - 1)))
            {
                // address is ok regarding the single @ sign
                return (Regex.IsMatch(sEmail, @"(\w+)@([\w\-]+)\.(\w+)"));
            }
            else
            {
                return false;
            }
        }
        public static bool isDate(string strDate)
        {
            string valuePassed = string.Empty;
            valuePassed = strDate;
            DateTime dt = DateTime.MinValue;

            try
            {
                string strRegex = @"^\d{4}([/])\d{1,2}([/])\d{1,2}$";
                Regex re = new Regex(strRegex);
                if (!re.IsMatch(strDate))
                    return false;

                IFormatProvider format = new CultureInfo("en-US");

                dt = DateTime.Parse(valuePassed, format, DateTimeStyles.None);
                return true;
            }
            catch
            {
                return false;
            }
        }

        //protected bool isNullOrEmpty(object obj)
        //{
        //    try
        //    {
        //        if (obj == null)
        //            return true;
        //        if (obj.ToString().Trim().Equals(""))
        //            return true;
        //        return false;
        //    }
        //    catch
        //    {
        //        return false;
        //    }
        //}
        public static bool isDateTime(string pDate)
        {
            try
            {
                DateTime A = DateTime.Parse(pDate);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public static bool isDateTime(string pDate, string pDateFormat)
        {
            try
            {
                DateTime A = parseDateTime(pDate, pDateFormat);
                return true;
            }
            catch
            {
                return false;
            }
        }

        public bool isInteger(string pNum)
        {
            try
            {
                int A = Convert.ToInt32(pNum);
                return true;
            }
            catch
            {
                return false;
            }
        }
        public bool isDouble(string pNum)
        {
            try
            {
                double A = Convert.ToDouble(pNum);
                return true;
            }
            catch
            {
                return false;
            }
        }
        #endregion

        #region Converting
        public static DateTime parseDateTime(object obj, string format)
        {
            DateTimeFormatInfo dtfi = new DateTimeFormatInfo();
            dtfi.ShortDatePattern = format;
            dtfi.DateSeparator = "/";

            return Convert.ToDateTime(obj, dtfi);
        }

        public static DateTime? parseNullableDateTime(object obj, string format)
        {
            DateTimeFormatInfo dtfi = new DateTimeFormatInfo();
            dtfi.ShortDatePattern = format;
            dtfi.DateSeparator = "/";
            if (isNullOrEmpty(obj))
                return null;
            else if (!isDateTime(obj.ToString(), format))
                return null;
            return Convert.ToDateTime(obj, dtfi);
        }

        public static long parseLong(object obj)
        {
            try
            {
                if (isNullOrEmpty(obj))
                    return 0;
                return long.Parse(obj.ToString());
            }
            catch
            {
                return 0;
            }
        }
        public static int parseInt(object obj)
        {
            try
            {
                if (isNullOrEmpty(obj))
                    return 0;
                return int.Parse(obj.ToString());
            }
            catch
            {
                return 0;
            }
        }
        public static double parseDouble(object obj)
        {
            try
            {
                if (isNullOrEmpty(obj))
                    return 0;
                return double.Parse(obj.ToString());
            }
            catch
            {
                return 0;
            }
        }
        public static float parseFloat(object obj)
        {
            try
            {
                if (isNullOrEmpty(obj))
                    return 0;
                return Convert.ToSingle(obj.ToString());
            }
            catch
            {
                return 0;
            }
        }
        public static decimal parseDecimal(object obj)
        {
            try
            {
                if (isNullOrEmpty(obj))
                    return 0;
                return decimal.Parse(obj.ToString());
            }
            catch
            {
                return 0;
            }
        }
        public static decimal parseDecimal(object obj, NumberStyles style)
        {
            try
            {
                if (isNullOrEmpty(obj))
                    return 0;
                return decimal.Parse(obj.ToString(), style);
            }
            catch
            {
                return 0;
            }
        }
        public static string parseString(object obj)
        {
            try
            {
                if (isNullOrEmpty(obj))
                    return "";
                return obj.ToString();
            }
            catch
            {
                return "";
            }
        }

        public static bool parseBoolean(object obj)
        {
            try
            {
                if (isNullOrEmpty(obj))
                    return false;
                return Convert.ToBoolean(obj.ToString());
            }
            catch
            {
                return false;
            }
        }
        //Convert Datetime to String with specific format
        public static string parseString(DateTime? date, string format)
        {
            try
            {
                if (isNullOrEmpty(date))
                    return "";
                return date.Value.ToString(format);
            }
            catch
            {
                return "";
            }
        }

        public static string ConvertNumberToWord(string str)
        {
            string strNum1 = "";
            string strNum2 = "";
            string total = "";
            string strTemp = "";
            string strTemp2 = "";
            string result = "";
            str = str.Replace(",", "");

            if (str.Contains('.'))
            {
                strNum1 = ConvertToWord(Convert.ToInt64(str.Substring(str.IndexOf('.') + 1, str.Length - str.IndexOf('.') - 1)));
                if (str.Contains(','))
                {
                    strTemp = str.Substring(0, str.IndexOf(','));
                    strTemp2 = str.Substring(strTemp.ToString().Length + 1, str.Length - (strTemp.ToString().Length + 4));
                    total = strTemp.ToString() + strTemp2.ToString();
                }
                else
                {
                    strTemp2 = str.Substring(0, str.IndexOf('.'));
                    total = strTemp2.ToString();
                }
                strNum2 = ConvertToWord(Convert.ToInt64(total));

                if (strNum1 != "")
                {
                    return result = strNum2 + " USD AND " + strNum1 + " PENCES";
                }
                else
                {
                    return result = strNum2 + " USD";
                }
            }
            else
            {
                return result = ConvertToWord(Convert.ToInt64(str)) + " USD ";
            }
        }
        public static string ConvertToWord(long nNumber)
        {
            long CurrentNumber = nNumber;
            string sReturn = "";

            if (CurrentNumber >= 1000000000)
            {
                sReturn = sReturn + " " + GetWord(CurrentNumber / 1000000000, "BILLION");
                CurrentNumber = CurrentNumber % 1000000000;
            }
            if (CurrentNumber >= 1000000)
            {
                sReturn = sReturn + " " + GetWord(CurrentNumber / 1000000, "MILLION");
                CurrentNumber = CurrentNumber % 1000000;
            }
            if (CurrentNumber >= 1000)
            {
                sReturn = sReturn + " " + GetWord(CurrentNumber / 1000, "THOUSAND");
                CurrentNumber = CurrentNumber % 1000;
            }
            if (CurrentNumber >= 100)
            {
                sReturn = sReturn + " " + GetWord(CurrentNumber / 100, "HUNDRED");
                CurrentNumber = CurrentNumber % 100;
            }
            if (CurrentNumber >= 20)
            {
                sReturn = sReturn + " " + GetWord(CurrentNumber, "");
                CurrentNumber = CurrentNumber % 10;
            }
            else if (CurrentNumber > 0)
            {
                sReturn = sReturn + " " + GetWord(CurrentNumber, "");
                CurrentNumber = 0;
            }
            return sReturn.Replace("  ", " ").Trim();
        }
        private static string GetWord(long nNumber, string sPrefix)
        {
            long nCurrentNumber = nNumber;
            string sReturn = "";
            while (nCurrentNumber > 0)
            {
                if (nCurrentNumber > 100)
                {
                    sReturn = sReturn + " " + GetWord(nCurrentNumber / 100, "HUNDRED");
                    nCurrentNumber = nCurrentNumber % 100;
                }
                else if (nCurrentNumber > 20)
                {
                    sReturn = sReturn + " " + GetTwentyWord(nCurrentNumber / 10);
                    nCurrentNumber = nCurrentNumber % 10;
                }
                else
                {
                    sReturn = sReturn + " " + GetLessThanTwentyWord(nCurrentNumber);
                    nCurrentNumber = 0;
                }
            }
            sReturn = sReturn + " " + sPrefix;
            return sReturn;
        }
        private static string GetTwentyWord(long nNumber)
        {
            string sReturn = "";
            switch (nNumber)
            {
                case 2:
                    sReturn = "TWENTY";
                    break;
                case 3:
                    sReturn = "THIRTY";
                    break;
                case 4:
                    sReturn = "FORTY";
                    break;
                case 5:
                    sReturn = "FIFTY";
                    break;
                case 6:
                    sReturn = "SIXTY";
                    break;
                case 7:
                    sReturn = "SEVENTY";
                    break;
                case 8:
                    sReturn = "EIGHTY";
                    break;
                case 9:
                    sReturn = "NINETY";
                    break;
            }
            return sReturn;
        }
        private static string GetLessThanTwentyWord(long nNumber)
        {
            string sReturn = "";
            switch (nNumber)
            {
                case 1:
                    sReturn = "ONE";
                    break;
                case 2:
                    sReturn = "TWO";
                    break;
                case 3:
                    sReturn = "THREE";
                    break;
                case 4:
                    sReturn = "FOUR";
                    break;
                case 5:
                    sReturn = "FIVE";
                    break;
                case 6:
                    sReturn = "SIX";
                    break;
                case 7:
                    sReturn = "SEVEN";
                    break;
                case 8:
                    sReturn = "EIGHT";
                    break;
                case 9:
                    sReturn = "NINE";
                    break;
                case 10:
                    sReturn = "TEN";
                    break;
                case 11:
                    sReturn = "ELEVEN";
                    break;
                case 12:
                    sReturn = "TWELVE";
                    break;
                case 13:
                    sReturn = "THIRTEEN";
                    break;
                case 14:
                    sReturn = "FORTEEN";
                    break;
                case 15:
                    sReturn = "FIFTEEN";
                    break;
                case 16:
                    sReturn = "SIXTEEN";
                    break;
                case 17:
                    sReturn = "SEVENTEEN";
                    break;
                case 18:
                    sReturn = "EIGHTEEN";
                    break;
                case 19:
                    sReturn = "NINETEEN";
                    break;
            }
            return sReturn;
        }
        public static string splipString(string value, char keySplip)
        {
            if (value.Contains(keySplip))
            {
                string[] s = value.Split(keySplip);

                return s[0].ToString();
            }
            else
            {
                return value;
            }


        }
        public static string Md5Encrypt(string toEncrypt, bool useHashing)
        {
            byte[] keyArray;
            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(toEncrypt);

            System.Configuration.AppSettingsReader settingsReader =
                                                new AppSettingsReader();
            // Get the key from config file

            //string key = (string)settingsReader.GetValue("SecurityKey",
            //                                                 typeof(String));
            string key = "abcdef";
            //System.Windows.Forms.MessageBox.Show(key);
            //If hashing use get hashcode regards to your key
            if (useHashing)
            {
                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
                //Always release the resources and flush data
                // of the Cryptographic service provide. Best Practice

                hashmd5.Clear();
            }
            else
                keyArray = UTF8Encoding.UTF8.GetBytes(key);

            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            //set the secret key for the tripleDES algorithm
            tdes.Key = keyArray;
            //mode of operation. there are other 4 modes.
            //We choose ECB(Electronic code Book)
            tdes.Mode = CipherMode.ECB;
            //padding mode(if any extra byte added)

            tdes.Padding = PaddingMode.PKCS7;

            ICryptoTransform cTransform = tdes.CreateEncryptor();
            //transform the specified region of bytes array to resultArray
            byte[] resultArray =
              cTransform.TransformFinalBlock(toEncryptArray, 0,
              toEncryptArray.Length);
            //Release resources held by TripleDes Encryptor
            tdes.Clear();
            //Return the encrypted data into unreadable string format
            return Convert.ToBase64String(resultArray, 0, resultArray.Length);
        }
        public static string Md5Decrypt(string cipherString, bool useHashing)
        {
            byte[] keyArray;
            //get the byte code of the string

            byte[] toEncryptArray = Convert.FromBase64String(cipherString);

            System.Configuration.AppSettingsReader settingsReader =
                                                new AppSettingsReader();
            //Get your key from config file to open the lock!
            // string key = (string)settingsReader.GetValue("SecurityKey",
            //                                             typeof(String));
            string key = "abcdef";
            if (useHashing)
            {
                //if hashing was used get the hash code with regards to your key
                MD5CryptoServiceProvider hashmd5 = new MD5CryptoServiceProvider();
                keyArray = hashmd5.ComputeHash(UTF8Encoding.UTF8.GetBytes(key));
                //release any resource held by the MD5CryptoServiceProvider

                hashmd5.Clear();
            }
            else
            {
                //if hashing was not implemented get the byte code of the key
                keyArray = UTF8Encoding.UTF8.GetBytes(key);
            }

            TripleDESCryptoServiceProvider tdes = new TripleDESCryptoServiceProvider();
            //set the secret key for the tripleDES algorithm
            tdes.Key = keyArray;
            //mode of operation. there are other 4 modes. 
            //We choose ECB(Electronic code Book)

            tdes.Mode = CipherMode.ECB;
            //padding mode(if any extra byte added)
            tdes.Padding = PaddingMode.PKCS7;

            ICryptoTransform cTransform = tdes.CreateDecryptor();
            byte[] resultArray = cTransform.TransformFinalBlock(
                                 toEncryptArray, 0, toEncryptArray.Length);
            //Release resources held by TripleDes Encryptor                
            tdes.Clear();
            //return the Clear decrypted TEXT
            return UTF8Encoding.UTF8.GetString(resultArray);
        }
        public static string MD5Encrypt(string value)
        {
            MD5CryptoServiceProvider s_md5 = null;
            if (s_md5 == null) //creating only when needed
                s_md5 = new MD5CryptoServiceProvider();
            Byte[] newdata = Encoding.Default.GetBytes(value);
            Byte[] encrypted = s_md5.ComputeHash(newdata);
            return BitConverter.ToString(encrypted).Replace("-", "");
        }
        public static string filterCharSQl(string text)
        {

            string result = text;
            if (text.Contains("\\"))
            {
                result = text.Replace("\\", "\\");
            }

            if (text.Contains("'"))
            {
                result = text.Replace("'", "\\'");
            }

            return result;
        }
        public static void LogError(string error)
        {
            try
            {
                string pathServer = Environment.CurrentDirectory;
                string path = "";
                if (pathServer.Contains("Template"))
                    path = Environment.CurrentDirectory + "\\FileError.txt";
                else
                    path = Environment.CurrentDirectory + "\\Template\\FileError.txt";
                if (!System.IO.File.Exists(path))
                {
                    System.IO.File.Create(path);
                }
                System.IO.StreamWriter Tex = new System.IO.StreamWriter(path, true);
                Tex.WriteLine(DateTime.Now.ToString("dd/MM/yyyy HH:mm:ss").ToUpper() + " : " + error);
                Tex.Write(Tex.NewLine);
                Tex.Close();
            }
            catch { }
        }

        public static int GetNumberOfRow()
        {
            try
            {
                return 15;
            }
            catch (Exception ex)
            {
                //Write log
                return 15;
            }
        }

        public static string TruncateURL(string url)
        {
            if (url.IndexOf("/") == 0)
            {
                url = url.Remove(0, 1);
            }

            if (url.LastIndexOf("/") == url.Length - 1)
            {
                url = url.Remove(url.Length - 1, 1);
            }
            return url;
        }
        #endregion

        #region Encrypt Algorithms

        /// <summary>
        /// Encrypt password by MD5 Algorithm
        /// </summary>
        /// <param name="password">Password</param>
        /// <returns>String is encrypt</returns>
        /// <author>NHKhuong<author>
        public static string GetMD5EncyptString(string password)
        {
            MD5CryptoServiceProvider md5Hasher = new MD5CryptoServiceProvider();
            byte[] hashedBytes;
            UTF8Encoding encoder = new UTF8Encoding();
            hashedBytes = md5Hasher.ComputeHash(encoder.GetBytes(password));
            string str_md5 = string.Empty;

            foreach (byte b in hashedBytes)
            {
                str_md5 += b.ToString("X2");
            }

            return str_md5;
        }

        #endregion

        #region Datatable handle
        public static DataTable CustomizeData(DataTable _dtInput, string[] _colName)
        {
            DataTable dtResult=_dtInput.Copy();
            for (int i = 0; i < _colName.Length; i++)
            {
                if (!dtResult.Columns.Contains(_colName[i]))
                    dtResult.Columns.Add(_colName[i]);
            }
            return dtResult;
        }

        //Get property name
        public static string GetPropertyName<T>(Expression<Func<T>> property)
        {
            return (((MemberExpression)(property.Body)).Member).Name;

        }
        #endregion

        public static int GetNumberPerPage(int defaultVal = 20)
        {

            int result = defaultVal;
            try
            {
                string s = GetValueWebconfig("NumberPerPage");
                int.TryParse(s, out result);
            }
            catch
            {
                result = defaultVal;
            }
            return result;
        }
        private static string GetValueWebconfig(string key)
        {
            string result = null;
            try
            {
                result = WebConfigurationManager.AppSettings[key].ToString();
            }
            catch
            {
                result = null;
            }
            return result;
        }

       
    }
}
